package SWFData;


import java.io.BufferedWriter;
import java.io.File;
import java.util.*;


import myio.*;
import mymath.*;

import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.Document;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.XMLWriter;
import org.dom4j.io.SAXReader;


public class SWFparsexml {

	/**
	 * @param args
	 */
	
private static int CLUSTERORDINAL = 0;
private static int CLUSTERCATEGORICAL = 1;

/* Also print the occurrence data in the .mrf file?
 * Used to transform data in .mrf format to a simple 
 * table format for use with R 
 */
private static boolean PRINTDATA = false;

private class plantrecord{

	int id;
	String name;
	
	private plantrecord(int idarg, String namearg){
		id = idarg;
		name = namearg;
	}
	
	private int getId(){
		return id;
	}
	
	private String getName(){
		return name;
	}
}


/* 
 *  Reads the clusterassignments contained in xml format in clusterfile.
 *  If clusterfile contains k clusterings for n instances, then method
 *  returns an (k+1) x (n+1) array. The first entry in each row is an indicator
 *  for the type of the clustering: ordinal or categorical. 
 *  The last row contains an index for the clustercombination of the first 
 *  k rows.
 */
private static int[][] readClusters(String clusterfile){
	int[][] result = null;
	
	
	try{
		SAXReader reader = new SAXReader();
		File xmlfile = new File(clusterfile);
		Document doc = reader.read(xmlfile);
		Element root = doc.getRootElement();

		List<Element> instlist = root.elements("Inst");
		int numinstances = instlist.size();

		Element firstinst = instlist.get(0);
		List<Element> cluslist = firstinst.elements("Clus");
		int numclusterings = cluslist.size();
		int[] clusdims = new int[numclusterings]; /* contains for each clustering the number of clusters in that
		clustering */
		result = new int[numclusterings+1][numinstances +1];

		/* Determine the types of clusterings 
		 * 
		 * It is assumed that categorical clusterings have clusterlabels of the form cX (X an integer)
		 * and ordinal clusterings have integer clusterlabels 
		 * */

		for (int  i = 0; i< cluslist.size();i++){
			Element nextclus = cluslist.get(i);
			String clusval = nextclus.attributeValue("val").trim();
			if (clusval.charAt(0) == 'c')
				result[i][0] = CLUSTERORDINAL;
			else
				result[i][0] = CLUSTERCATEGORICAL;
		}

		
		/* 
		 *  Now fill in the actual cluster indices
		 */
		int thisindex;
		
		for (int  j = 0; j< instlist.size();j++){
			Element nextinst = instlist.get(j);
			cluslist = nextinst.elements("Clus");
			for (int  i = 0; i< cluslist.size();i++){
				int thisclustype = result[i][0];
				Element nextclus = cluslist.get(i);
				String clusval = nextclus.attributeValue("val").trim();
				if (thisclustype == CLUSTERORDINAL)
					thisindex = Integer.parseInt(clusval.substring(1));
				else 
					thisindex = Integer.parseInt(clusval);
				result[i][j+1] = thisindex;
				clusdims[i]=Math.max(clusdims[i],thisindex+1);
			}		
		}
		/* 
		 *  Fill in the row with the combined index
		 */
		int[] instclusterings = new int[numclusterings];
		for (int  j = 0; j< instlist.size();j++){
			for (int i=0;i<numclusterings;i++)
				instclusterings[i] = result[i][j];
			result[numclusterings][j]= MyMathOps.arraytoindex(instclusterings,clusdims);
		}
	}

	catch (Exception e) {
		System.err.println(e);
	}
	return result;
}

/* Creates a colored map in xfig format. 
 * mapfile is a datafile in .mrf format that 
 * supplies in its <Points> fields the polygon
 * vertices defining the sites. clsterindices is 
 * an array with as many entries as there are
 * <Site> elements in the mapfile.  
 */
public static void makeXFIGmap(String mapfile, int[] clusterindices, String outfilename ){


	try{
		SAXReader reader = new SAXReader();
		File xmlfile = new File(mapfile);
		Document doc = reader.read(xmlfile);
		Element root = doc.getRootElement();



			/* Prepare the outputfile: */
			BufferedWriter figwriter = FileIO.openOutputFile(outfilename);
			figwriter.write("#FIG 3.2" + '\n' + 
					"Landscape" + '\n' + 
					"Center" + '\n' + 
					"Metric" + '\n' + 
					"A4"      + '\n' + 
					"100.00" + '\n' + 
					"Single" + '\n' + 
					"-2 "+ '\n' + 
					"1200 2" + '\n' +
					"0 50 #007599"   + '\n' +
					"0 51 #5da591"   + '\n' +
					"0 52 #fca537"   + '\n' +
					"0 53 #7f6b37"   + '\n' +
					"0 54 #a2ff00"   + '\n' +
					"0 55 #a2ffff"   + '\n' +
					"0 56 #ffff1b"   + '\n' +
					"0 57 #c5b3ff"   + '\n' +
					"0 58 #c5b318"   + '\n' 
			);

			/* Iterate over all sites */
			Element sitesel = root.element("Sites");
			int siteno = 0;
			for (Iterator<Element> i = sitesel.elementIterator("Site");i.hasNext();siteno++){
				Element siteel = i.next();
				Element polygonel = siteel.element("Points");
				//System.out.print(siteno + ": "); 
				List<Element> pointlist = polygonel.elements("Point");
				figwriter.write("2 3 0 1 0 ");
				int col = 50 + clusterindices[1+siteno];
				figwriter.write(col + " ");
				figwriter.write("50 -1 20 0.000 0 0 -1 0 0 " + pointlist.size() + '\n');

				for (Iterator<Element> ii = pointlist.iterator();ii.hasNext();){
					Element pointel = ii.next();
					int xcoord = Integer.parseInt(pointel.attributeValue("X"));
					int ycoord = Integer.parseInt(pointel.attributeValue("Y"));
					figwriter.write(xcoord + " " + ycoord + " ");
				}
				figwriter.write('\n');
			}

			figwriter.close();
	}
	catch (Exception e) {
		System.err.println(e);
	}
}

/* args[0]: the xml specification of the map
 * args[1]: the R-generated file with the clusterings
 */
public static void main(String[] args) {

	try{
		SAXReader reader = new SAXReader();

		File xmlfile = new File(args[0]);
		Document doc = reader.read(xmlfile);
		Element root = doc.getRootElement();
		Element preamel = root.element("MetaData");


		
		/* collect the plant variables in an array with their names */

		Vector<String> plantnames = new Vector<String>();
		/*
		 * Maps the plant identifiers to consecutive indices 
		 */
		TreeMap<Integer,Integer> idtoindex = new TreeMap<Integer,Integer>();
		
		Element plantvars = preamel.element("DiscreteVariables");
		List<Element> plantvarslist = preamel.elements("DiscreteVariable");
		
		int plantcount = 0;
		for (Iterator<Element> i = plantvars.elementIterator("DiscreteVariable"); i.hasNext();plantcount++){
			Element plantel = i.next();
			plantnames.add(plantel.attributeValue("Name").replaceAll(" ", "_"));
			idtoindex.put(Integer.parseInt(plantel.attributeValue("ID")),plantcount);
		}

		if (PRINTDATA){
			for (int k=0;k<plantnames.size();k++)
				System.out.print(plantnames.elementAt(k) + " ");
			System.out.println();
		}



		Element sitesel = root.element("Sites");

		int caseno = 0;

		for (Iterator<Element> i = sitesel.elementIterator("Site");i.hasNext();caseno++){
			Element siteel = i.next();
			int[] dataarray = new int[plantnames.size()];
			Element variables = siteel.element("DiscreteVariables");
			for (Iterator<Element> ii = variables.elementIterator("DiscreteVariable");ii.hasNext();){
				Element variable = ii.next();
				int value = Integer.parseInt(variable.attributeValue("Value"));
				if ( value == 3 || value ==2)
					dataarray[idtoindex.get(Integer.parseInt(variable.attributeValue("ID")))]=1;

				//					else
				//						throw new Exception("unexpected value " + value);
			}
			if (PRINTDATA){
				System.out.print(caseno + " ");
				for (int k=0;k<plantnames.size();k++)
					System.out.print(dataarray[k] + " ");
				System.out.println();
			}
		}
		//			List<Element> siteslist = sitesel.elements("Site");

	}
	catch (Exception e) {
		System.err.println(e);
	}

	/* Reading the clustering information */
	int[][] clusterings = readClusters(args[1]);

	/* Writing the xfig maps: */
	String baseoutname = args[1]+"_layer_";
	for (int layer=0;layer<clusterings.length-1;layer++){
		makeXFIGmap(args[0], clusterings[layer], baseoutname+layer+".fig");
	}
		makeXFIGmap(args[0], clusterings[clusterings.length-1], baseoutname+"combined.fig");
}

}
